/*  PrimeBlaster
    by Kjetil Eide 
    kjetile445@gmail.com

    This file is part of PrimeBlaster

    PrimeBlaster is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    PrimeBlaster is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with PrimeBlaster.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.eide.spaceship;

import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Line;

public class MainGame extends BasicGameState {
	/** The ID given to this state */
	public static final int ID = 3;

	/** The game holding this state */
	private StateBasedGame game;
		
	/*
	 * delta is the number of milliseconds between each call to the update()
	 * method. delta is divided by PROGRAM_SPEED to give timeStep, which
	 * specifies how far ahead in time we integrate on each update() call.
	 * position += velocity (delta/PROGRAM_SPEED) lower values of PROGRAM_SPEED
	 * means the objects will move faster on screen.
	 */	
	private static final float PROGRAM_SPEED = 200f;
	private float timeStep;
	
	private static final float SHIP_INITIAL_X = 100;
	private static final float SHIP_INITIAL_Y = 100;
		
	/* Collection containing all the rigid bodies
	 * Stored in an ArrayList in RBCollection object.
	 * Walls have index 0-3
	 * SpaceShip have index SHIP
	 * Asteroids have index >SHIP
	 */
	private RBCollection rBody;
	
	private SpaceGraphics spaceGraphics;
	private Laser laser;
	
	public static Line[] debugGfx = new Line[5];
	
	/* used for waiting a while before we quit after player is dead */
	private long endGameTimeCounter; 
	private PlayerStatus playerStatus;
	
	/* holds all the image data, fonts and animations used by the game */
	ImageData gfxData;
	
	/* holds all the sound data for the game */
	SoundData sound;
	
	public MainGame(PlayerStatus playerStatus) {
		this.playerStatus = playerStatus;
	}
	
	/**
	 * @see org.newdawn.slick.state.BasicGameState#getID()
	 */
	public int getID() {
		return ID;
	}

	public void init(GameContainer container, StateBasedGame game) throws SlickException {
		this.game = game; 
	
		gfxData = new ImageData();
		sound = new SoundData();
		rBody = new RBCollection(gfxData);
		
		/* Top wall */
		rBody.addWall((float) PrimeBlaster.SCREEN_WIDTH / 2, 5f, 
	            (float) PrimeBlaster.SCREEN_WIDTH-22, 10f, 0);
				
		/* right wall */
		rBody.addWall((float) PrimeBlaster.SCREEN_WIDTH - 5f,
				(float) PrimeBlaster.SCREEN_HEIGHT / 2,
				10f, (float) PrimeBlaster.SCREEN_HEIGHT - 22, 1);

		/* bottom wall */		
		rBody.addWall((float) PrimeBlaster.SCREEN_WIDTH / 2,
				(float) PrimeBlaster.SCREEN_HEIGHT - 5f,
				(float) PrimeBlaster.SCREEN_WIDTH - 22,
				10f, 0);
		
		/* left wall */		
		rBody.addWall(5f, (float) PrimeBlaster.SCREEN_HEIGHT / 2,
				10f, 
				(float) PrimeBlaster.SCREEN_HEIGHT - 22, 1);		

		rBody.addShip(SHIP_INITIAL_X, SHIP_INITIAL_Y);
		
		spaceGraphics = new SpaceGraphics(PrimeBlaster.SCREEN_WIDTH, PrimeBlaster.SCREEN_HEIGHT);
		
		for (int i = 0; i < debugGfx.length; i++) {
			debugGfx[i] = new Line(0, 0, 0, 0);
		}
		
		laser = new Laser(Math.max(PrimeBlaster.SCREEN_WIDTH, PrimeBlaster.SCREEN_HEIGHT), rBody.getShip());
	}

	public void update(GameContainer container, StateBasedGame game, int delta)
			throws SlickException {
		/*
		 * numbers of seconds since last call to update() (when PROGRAM_SPEED =
		 * 1000) this is the timeStep we want to use for integration
		 */

		timeStep = delta / PROGRAM_SPEED;

		/*
		 * used for subdividing timestep when objects are penetrating
		 */
		float targetTime = timeStep;

		/* how far have we integrated so far */
		float currentTime = 0;

		while (currentTime < timeStep) {

			if (!playerStatus.levelFinished()) {
				rBody.getShip().control(container, timeStep);
				laser.control(container);
				if (laser.isOn()) {
					laser.update(rBody.getShip());
					Asteroid hit = laser.checkHit(RBCollection.SHIP, rBody,
							delta);
					rBody.updateAsteroidState(hit, playerStatus, delta);
					
					/* updateAsteroidState() may have killed the player
					 * check if player now is dead 
					 */
					if (playerStatus.isDead()) {
						laser.reset();
						playerStatus.setFailedNumber(hit.getDisplayNumber());
						endGameTimeCounter = System.currentTimeMillis();
					} else if(playerStatus.levelFinished()) {
						endGameTimeCounter = System.currentTimeMillis();
						rBody.removeAllAsteroids();
						laser.reset();
						//laser.turnOff();
					}
					
				}
				if (rBody.getShip().isInvincible() &&
						(System.currentTimeMillis() - rBody.getShip().getInvincibleTimer() > 3000)) {
					rBody.getShip().setInvincible(false);	
				}
				rBody.updateShipState(playerStatus);
				
				if (playerStatus.isDead()) {
					laser.reset();
					endGameTimeCounter = System.currentTimeMillis();
				}
				
				rBody.getShip().configureEngineFlames(delta);
				
				//if(container.getInput().isKeyDown(Input.KEY_TAB)) {
				//	playerStatus.evaluatePlayer(rBody);
				//	endGameTimeCounter = System.currentTimeMillis();
				//}				
			} else {
				
				/* level is finished.
				 * either the player has completed the level or is dead
				 */
				laser.reset();
				if ((System.currentTimeMillis() - endGameTimeCounter) > 4000) {
					if (playerStatus.isDead()) {
						playerStatus.setLevel(0);
						game.enterState(TitleScreen.ID);
					} else {
						game.enterState(LevelGetReady.ID);
					}
				}
			}
			if (rBody.getExplosion() != null) {
				//System.out.println("Fant explosion");
				//System.out.println("frame:" +rBody.getExplosion().getAnim().getFrame());
				if (rBody.getExplosion().getAnim().isStopped()) {
					//System.out.println("fjerner");
					rBody.removeExplosion();
				}
			}
			
			
			rBody.simulate(timeStep);
			rBody.doCollision();

			currentTime = targetTime;
			targetTime = timeStep;
		}
	}

	public void render(GameContainer container, StateBasedGame game, Graphics g)
			throws SlickException {
		
		//Graphics.setCurrent(g);
		
		spaceGraphics.drawBG(g);
		
		
		for (int i = 0; i < rBody.getNumberOfRB(); i++) {
			spaceGraphics.drawBody(rBody.getRB(i), g);
		}
		
		spaceGraphics.drawFlame(rBody.getShip().getFlame());
		spaceGraphics.drawLaser(laser, g);
		
		if (playerStatus.levelFinished()) {
			if (playerStatus.isDead()) {
				if (playerStatus.getFailedNumber() > 0) {
					spaceGraphics.drawMsg(playerStatus.getFailedNumber() + " is a prime number!", gfxData.getFont(), g);
				} else {
					spaceGraphics.drawMsg("You failed!", gfxData.getFont(), g);
				}
			} else {
				spaceGraphics.drawMsg("Well done!", gfxData.getFont(), g);
			}
		} else {
			spaceGraphics.drawStatus(rBody.getShip().getStrength());
		}
		
		if (rBody.getExplosion() != null) {
			spaceGraphics.drawExplosion(rBody.getExplosion(), g);
		}
	}
	
	public void enter(GameContainer c, StateBasedGame game) throws SlickException {
		super.enter(c, game);
		rBody.removeAllAsteroids();
		rBody.getShip().reset(SHIP_INITIAL_X, SHIP_INITIAL_Y);
		rBody.generateRandomAsteroids(playerStatus);
		playerStatus.reset();
		laser.reset();
	}
	
}